package com.corticon.dialogs.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.OneToMany;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;

import org.hibernate.validator.Length;


/**
 * @author Lifan Yang
 */
@NamedQueries( { @NamedQuery(name = "Question.findMaxRefId", query = "select max(q.refId) from Question q") })
@Entity
@Table(name = "q_question", uniqueConstraints = { @UniqueConstraint(columnNames = { "ID", "VERSION" }) })
public class Question extends QuestionBase implements Serializable {

	private Long questionId;

	// ********** Question Properties ********** //
	private Question sibling;
	private Set<QuestionInSet> questionInSets = new HashSet<QuestionInSet>();
	// These two type params can be and should be insteaded of enum.
	private QuestionStatusType questionStatusType;
	private QuestionAvailabilityType questionAvailabilityType;

	// ********** Response Properties ********** //
	private ResponseType responseType;
	// private Set<Response> responses = new HashSet<Response>();
	private String defaultResponseValue;
	private String epaRefQuestionnaires;
	private String epaResponseDataType;
	private String maxResponseValue;
	private Boolean maxResponseValueInclusive;
	private Long maxResponses;
	private String minResponseValue;
	private Boolean minResponseValueInclusive;
	private String width;
	private String rows;

	/* Transient Properties */
	private List<ResponseEntry> dynamicResponseEntries = new ArrayList<ResponseEntry>();

	public Question() {
	}

	public Question(String refId, long version) {
		this.refId = refId;
		this.version = version;
	}

	public Question(String refId, long version, QuestionStatusType status, QuestionAvailabilityType availability) {
		this.refId = refId;
		this.version = version;
		this.questionStatusType = status;
		this.questionAvailabilityType = availability;
	}

	@Id
	// @SequenceGenerator(name = "Q_Question_Q_Question_ID_seq", sequenceName =
	// "Q_Question_Q_Question_ID_seq")
	// @GeneratedValue(strategy = GenerationType.AUTO, generator =
	// "Q_Question_Q_Question_ID_seq")
	@SequenceGenerator(name = "q_question_id_seq", sequenceName = "q_question_id_seq", allocationSize = 1, initialValue = 1)
	// Set allocationSize and initialValue
	// to let sequence increment following DB.
	@GeneratedValue(strategy = GenerationType.AUTO, generator = "q_question_id_seq")
	@Column(name = "q_question_id", columnDefinition = "integer")
	public Long getQuestionId() {
		return this.questionId;
	}

	public void setQuestionId(Long questionId) {
		this.questionId = questionId;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "siblingqassoc_q_q_id_oid")
	public Question getSibling() {
		return this.sibling;
	}

	public void setSibling(Question sibling) {
		this.sibling = sibling;
	}

	@OneToMany(mappedBy = "question")
	public Set<QuestionInSet> getQuestionInSets() {
		return questionInSets;
	}

	public void setQuestionInSets(Set<QuestionInSet> questionInSets) {
		this.questionInSets = questionInSets;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "statusassoc_code_oid")
	public QuestionStatusType getQuestionStatusType() {
		return this.questionStatusType;
	}

	public void setQuestionStatusType(QuestionStatusType questionStatusType) {
		this.questionStatusType = questionStatusType;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "availabilityassoc_code_oid")
	public QuestionAvailabilityType getQuestionAvailabilityType() {
		return this.questionAvailabilityType;
	}

	public void setQuestionAvailabilityType(QuestionAvailabilityType questionAvailabilityType) {
		this.questionAvailabilityType = questionAvailabilityType;
	}

	@ManyToOne(fetch = FetchType.LAZY)
	@JoinColumn(name = "resptypeassoc_q_resptype_id_oi")
	public ResponseType getResponseType() {
		return this.responseType;
	}

	public void setResponseType(ResponseType responseType) {
		this.responseType = responseType;
	}

	// @OneToMany(cascade = CascadeType.ALL, mappedBy = "question", fetch =
	// FetchType.LAZY)
	// public Set<Response> getResponses() {
	// return this.responses;
	// }
	//
	// public void setResponses(Set<Response> responses) {
	// this.responses = responses;
	// }

	@Column(name = "defresponsevalue", length = 255)
	public String getDefaultResponseValue() {
		return this.defaultResponseValue;
	}

	public void setDefaultResponseValue(String defaultResponseValue) {
		this.defaultResponseValue = defaultResponseValue;
	}

	@Column(name = "eparefdialogs", length = 5000)
	public String getEpaRefQuestionnaires() {
		return this.epaRefQuestionnaires;
	}

	public void setEpaRefQuestionnaires(String epaRefQuestionnaires) {
		this.epaRefQuestionnaires = epaRefQuestionnaires;
	}

	@Column(name = "eparesponsedatatype", length = 255)
	public String getEpaResponseDataType() {
		return this.epaResponseDataType;
	}

	public void setEpaResponseDataType(String epaResponseDataType) {
		this.epaResponseDataType = epaResponseDataType;
	}

	@Length(max = 255, message = "question.maxresponsevalue.length")
	@Column(name = "maxresponsevalue", length = 255)
	public String getMaxResponseValue() {
		return this.maxResponseValue;
	}

	public void setMaxResponseValue(String maxResponseValue) {
		this.maxResponseValue = maxResponseValue;
	}

	@Column(name = "maxresponsevalueinclusive")
	public Boolean getMaxResponseValueInclusive() {
		return this.maxResponseValueInclusive;
	}

	public void setMaxResponseValueInclusive(Boolean maxResponseValueInclusive) {
		this.maxResponseValueInclusive = maxResponseValueInclusive == null ? false : maxResponseValueInclusive;
	}

	// @Column(name = "MAX_RESPONSES")
	@Column(name = "maxresponses")
	public Long getMaxResponses() {
		return this.maxResponses;
	}

	public void setMaxResponses(Long maxResponses) {
		this.maxResponses = maxResponses;
	}

	@Length(max = 255, message = "question.minresponsevalue.length")
	@Column(name = "minresponsevalue", length = 255)
	public String getMinResponseValue() {
		return this.minResponseValue;
	}

	public void setMinResponseValue(String minResponseValue) {
		this.minResponseValue = minResponseValue;
	}

	@Column(name = "minresponsevalueinclusive")
	public Boolean getMinResponseValueInclusive() {
		return this.minResponseValueInclusive;
	}

	public void setMinResponseValueInclusive(Boolean minResponseValueInclusive) {
		this.minResponseValueInclusive = minResponseValueInclusive;
	}

	@Length(max = 255, message = "question.width.length")
	@Column(name = "width", length = 255)
	public String getWidth() {
		return width;
	}

	public void setWidth(String width) {
		this.width = width;
	}

	@Length(max = 255, message = "question.rows.length")
	@Column(name = "rows_oid", length = 255)
	public String getRows() {
		return rows;
	}

	public void setRows(String rows) {
		this.rows = rows;
	}

	@Transient
	public List<ResponseEntry> getDynamicResponseEntries() {
		return dynamicResponseEntries;
	}

	public void setDynamicResponseEntries(List<ResponseEntry> dynamicResponseEntries) {
		this.dynamicResponseEntries = dynamicResponseEntries;
	}
}